package com.gem.netty.delay;

import com.gem.entity.Game;
import com.gem.entity.Room;
import com.gem.entity.User;
import com.gem.enums.ClientMessageType;
import com.gem.enums.MessageColorType;
import com.gem.factory.game.GameFactory;
import com.gem.factory.room.RoomFactory;
import com.gem.factory.user.UserFactory;
import com.gem.netty.entity.CurrentUser;
import com.gem.netty.session.GroupSession;
import com.gem.netty.session.GroupSessionFactory;
import com.gem.netty.session.Session;
import com.gem.netty.session.SessionFactory;
import com.gem.utils.R;
import io.netty.channel.Channel;

import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.DelayQueue;
import java.util.concurrent.Delayed;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * 长时间挂机用于踢人
 * Author: Xhy
 * CreateTime: 2022-10-07 15:34
 */
public class Heart  {

    private static Map<String,String> userIpMap = new ConcurrentHashMap<>();
    private static DelayQueue<DelayTask> delayQueue = new DelayQueue<>();
    private static ConcurrentHashMap<String,DelayTask> mapDelayQueue = new ConcurrentHashMap<>();



    private static volatile Heart heart;
    private Heart(){

    }
    public void remove(String ip){
        if (mapDelayQueue.containsKey(ip)) {
            DelayTask delayTask = mapDelayQueue.get(ip);
            if(delayQueue.remove(delayTask))
                mapDelayQueue.remove(ip);
        }

    }

    /**
     * 初始化一次
     * @return
     */
    public static Heart getInstance(){
        if (heart == null){
            synchronized (Heart.class){
                if (heart == null){
                    heart = new Heart();
                    monitor();
                }
            }
        }
        return heart;
    }

    public void add(String ip,long exprieTime){
        DelayTask task = new DelayTask(ip, exprieTime);
        if (ip !=null){
            mapDelayQueue.put(ip, task);
            // 此处忽略添加重复 key 的处理
            delayQueue.add(task);
        }

    }

    public void addUser(String ip,String userId){
        if (!userIpMap.containsKey(ip)){
            userIpMap.put(ip,userId);

        }
    }
    /**
     * 监听
     */
    private static void monitor(){
        Thread thread = new Thread(()->{
            while (true){
                DelayTask task = null;
                try {
                     task = delayQueue.take();
                    String ip = task.get();
                    final String userId = userIpMap.get(ip);
                    if(userId!=null){
                        // 断开连接
                        Session session = SessionFactory.getSession();
                        Channel channel = session.getChannel(userId);
                        // 删除用户
                        UserFactory.remove(userId);
                        mapDelayQueue.remove(ip);
                        userIpMap.remove(ip);
                        // 退出会话
                        SessionFactory.getSession().unbind(channel);
                        channel.close();
                        // 找到用户所在房间
                        Map<String, Room> roomMap = RoomFactory.listRooms();
                        roomMap.forEach((k,v)->{
                            if (RoomFactory.removeUser(v,userId)) {
                                // 通知其他人
                                List<Channel> channels = GroupSessionFactory.getGroupSession().getMembersChannel(k);
                                GameFactory.notifyUsers(channels,R.ok()
                                        .data("data",v.getRoomOwnerId())
                                        .data("color", MessageColorType.SYSTEM_MESSAGE.type)
                                        .message(UserFactory.get(userId)+"长时间挂机被踢出房间")
                                        .type(ClientMessageType.QUIT_ROOM.type),k);
                            }
                        });
                    }

                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

            }
        });
        thread.setName("长时间挂机断开连接thread");
        thread.setDaemon(true);
        thread.start();
    }

    public void reconnect(String ip) {
        if(mapDelayQueue.containsKey(ip)){
            DelayTask task = mapDelayQueue.get(ip);
            delayQueue.remove(task);
            mapDelayQueue.remove(ip);
        }
    }


    private class DelayTask implements Delayed {

        private String userId;
        /**
         * 过期时间(单位秒)
         */
        private long exprieTime;

        private long currentTime;

        public DelayTask(String userId, long exprieTime) {
            this.userId = userId;
            this.exprieTime = exprieTime;
            this.currentTime = System.currentTimeMillis();
        }

        @Override
        public long getDelay(TimeUnit unit) {
            // 计算剩余的过期时间
            // 大于 0 说明未过期
            return exprieTime - TimeUnit.MILLISECONDS.toSeconds(System.currentTimeMillis() - currentTime);
        }

        @Override
        public int compareTo(Delayed o) {
            // 过期时间长的放置在队列尾部
            if (this.getDelay(TimeUnit.MICROSECONDS) > o.getDelay(TimeUnit.MICROSECONDS)) {
                return 1;
            }
            // 过期时间短的放置在队列头
            if (this.getDelay(TimeUnit.MICROSECONDS) < o.getDelay(TimeUnit.MICROSECONDS)) {
                return -1;
            }

            return 0;
        }

        public String get() {
            return userId;
        }
    }
}
